﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;

namespace BesAsm.Emgaats.Maintenance
{
    public class UIArchiveLinksButton : ESRI.ArcGIS.Desktop.AddIns.Button
    {
        private ApplicationWindow _appWindow;

        public UIArchiveLinksButton()
        {
            _appWindow = new ApplicationWindow(ArcMap.Application.hWnd);
        }

        protected override void OnClick()
        {
            System.Windows.Forms.Cursor.Current = Cursors.WaitCursor;
            try
            {
                IActiveView activeView = ArcMap.Document.FocusMap as IActiveView;

                Configuration config = EmgaatsMaintenanceExtension.Extension.Configuration;
                IFeatureClass linkClass = config.MasterLinksEditClass;
                IFeatureLayer linkLayer = EmgaatsMaintenanceExtension.Extension.FindFeatureLayer(linkClass);
                int idField = linkClass.FindField("link_id");

                int copied = 0;
                int duplicates = 0;

                IFeatureSelection selection = linkLayer as IFeatureSelection;
                if (selection != null && selection.SelectionSet.Count > 0)
                {
                    IFeatureClass archiveClass = EmgaatsMaintenanceExtension.Extension.Settings.ArchiveClass;
                    IFeatureLayer archiveLayer = EmgaatsMaintenanceExtension.Extension.FindFeatureLayer(archiveClass);
                    if (archiveLayer != null)
                        archiveLayer.Cached = true;

                    List<int> archivedIds = _GetArchivedIds(archiveClass);
                    IFeatureCursor cursor = archiveClass.Insert(false);
                    try
                    {
                        IFeatureBuffer buffer = archiveClass.CreateFeatureBuffer();
                        IEnumIDs selectionIds = selection.SelectionSet.IDs;
                        int selectedId = selectionIds.Next();
                        while (selectedId > 0)
                        {
                            IFeature linkFeature = linkClass.GetFeature(selectedId);
                            try
                            {
                                if (linkFeature != null)
                                {
                                    int linkId = (int)linkFeature.get_Value(idField);
                                    if (!archivedIds.Contains(linkId))
                                    {
                                        buffer.Shape = linkFeature.ShapeCopy;

                                        // Copy all attributes
                                        for (int f = 0; f < linkFeature.Fields.FieldCount; f++)
                                        {
                                            IField fromField = linkFeature.Fields.get_Field(f);
                                            if (fromField.Type != esriFieldType.esriFieldTypeOID && fromField.Type != esriFieldType.esriFieldTypeGeometry)
                                            {
                                                int toFieldIndex = archiveClass.FindField(fromField.Name);
                                                if (toFieldIndex > -1)
                                                {
                                                    IField toField = archiveClass.Fields.get_Field(toFieldIndex);
                                                    if (toField.Editable)
                                                    {
                                                        object dbValue = DBNull.Value;
                                                        switch (toField.Name.ToLowerInvariant())
                                                        {
                                                            case "edited_by":
                                                                dbValue = Environment.UserName;
                                                                break;
                                                            case "edit_date":
                                                                dbValue = DateTime.Now;
                                                                break;
                                                            case "edit_reason":
                                                                dbValue = "delete";
                                                                break;
                                                            default:
                                                                if (toField.Type == fromField.Type)
                                                                {
                                                                    dbValue = linkFeature.get_Value(f);
                                                                }
                                                                break;
                                                        }
                                                        if (dbValue != DBNull.Value || toField.IsNullable)
                                                        {
                                                            buffer.set_Value(toFieldIndex, dbValue);
                                                        }
                                                    }
                                                }
                                            }
                                        }

                                        cursor.InsertFeature(buffer);
                                        copied++;
                                    }
                                    else
                                    {
                                        duplicates++;
                                    }
                                }
                            }
                            finally
                            {
                                EmgaatsMaintenanceExtension.ReleaseComObject(linkFeature);
                            }

                            selectedId = selectionIds.Next();
                        }
                        cursor.Flush();
                    }
                    finally
                    {
                        EmgaatsMaintenanceExtension.ReleaseComObject(cursor);
                    }

                    if (archiveLayer != null)
                    {
                        activeView.PartialRefresh(esriViewDrawPhase.esriViewGeography, archiveLayer, null);
                        archiveLayer.Cached = false;
                    }
                }
                else
                {
                    MessageBox.Show(_appWindow, "No link features are selected.", "No Selection", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

                MessageBoxIcon icon = MessageBoxIcon.Information;
                string message = string.Empty;
                if (copied == 1)
                {
                    message = "1 link was copied to the delete layer.";
                }
                else
                {
                    message = string.Format("{0} links were copied to the delete layer.", copied);
                }

                if (duplicates > 0)
                {
                    icon = MessageBoxIcon.Warning;
                    if (duplicates == 1)
                    {
                        message += Environment.NewLine + "1 was skipped because it has already been copied.";
                    }
                    else
                    {
                        message += Environment.NewLine + string.Format("{0} were skipped because they have already been copied.", duplicates);
                    }
                }
                MessageBox.Show(_appWindow, message, "Delete Links", MessageBoxButtons.OK, icon);
            }
            catch (Exception ex)
            {
                string msg = string.Format("An error occured: {0}", ex.Message);
                MessageBox.Show(_appWindow, msg, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                System.Windows.Forms.Cursor.Current = Cursors.Default;
            }
        }

        private List<int> _GetArchivedIds(IFeatureClass archiveClass)
        {
            List<int> archivedIds = new List<int>();

            int idField = archiveClass.FindField("link_id");
            if (idField > -1)
            {
                IFeatureCursor cursor = archiveClass.Search(null, false);
                try
                {
                    IFeature archiveFeature = cursor.NextFeature();
                    while (archiveFeature != null)
                    {
                        try
                        {
                            archivedIds.Add((int)archiveFeature.get_Value(idField));
                        }
                        finally
                        {
                            EmgaatsMaintenanceExtension.ReleaseComObject(archiveFeature);
                        }
                        archiveFeature = cursor.NextFeature();
                    }
                }
                finally
                {
                    EmgaatsMaintenanceExtension.ReleaseComObject(cursor);
                }
            }

            return archivedIds;
        }

        protected override void OnUpdate()
        {
            bool enabled = false;
            if (ArcMap.Application != null &&
                EmgaatsMaintenanceExtension.Extension != null &&
                EmgaatsMaintenanceExtension.Extension.Settings != null &&
                EmgaatsMaintenanceExtension.Extension.Settings.ArchiveClass != null &&
                EmgaatsMaintenanceExtension.Extension.LinkSelectionCount > 0)
            {
                enabled = true;
            }

            this.Enabled = enabled;
        }
    }
}
